package models

import (
	"context"
	"encoding/json"
	"github.com/ahmetb/go-linq/v3"
	"github.com/beego/beego/v2/client/orm"
	"strconv"
	"strings"
	"time"
)

type Role struct {
	BModel
	Memo   string `orm:"column(memo)" json:"memo"`
	Name   string `orm:"column(name)" json:"name"`
	Code   string `orm:"column(code)" json:"code"`
	Status uint8  `orm:"column(status)" json:"status"` //0->删除1->正常
	//RoleIds  string `orm:"column(role_ids)" json:"role_ids"`
}

//MarshalJSON 格式化时间
func (tb Role) MarshalJSON() ([]byte, error) {

	type Alias Role

	return json.Marshal(struct {
		Alias
		CreatedAt string `json:"created_at"`
		UpdatedAt string `json:"updated_at"`
	}{
		Alias:     (Alias)(tb),
		CreatedAt: tb.CreatedAt.Format("2006-01-02 15:04:05"),
		UpdatedAt: tb.UpdatedAt.Format("2006-01-02 15:04:05"),
	})
}
func NewRole() *Role {
	return &Role{}
}

func (*Role) TableName() string {
	return RoleTable
}

func (tb *Role) Find(id uint64) (m *Role, err error) {

	m = &Role{}
	db := orm.NewOrm()
	err = db.QueryTable(tb).Filter("id", id).One(m)
	if m.ID <= 0 {
		m = nil
	}
	return

}

func (tb *Role) GetByPage(pageSize, pageIndex uint64) (lst []Role, count uint64, err error) {

	offset := (pageIndex - 1) * pageSize
	db := orm.NewOrm()
	q := db.QueryTable(tb).Filter("status__gt", 0)
	c, e := q.Count()
	count = uint64(c)
	err = e
	if count <= 0 {

		return
	}
	_, err = q.Offset(offset).Limit(pageSize).All(&lst)
	return

}

func (tb *Role) GetList(ids []int) (lst []Role, err error) {

	db := orm.NewOrm()
	_, err = db.QueryTable(tb).Filter("status__gt", 0).Filter("id__in", ids).All(&lst)
	return

}
func (tb *Role) GetAll() (lst []Role, err error) {

	db := orm.NewOrm()
	_, err = db.QueryTable(tb).Filter("status__gt", 0).All(&lst)
	return

}

type AddRoleReq struct {
	Name string `json:"name"`
	Code string `json:"code"`
	Memo string `json:"memo"`
	MIds string `json:"menu_ids"`
}

func (tb *Role) Add(uid uint64, req AddRoleReq) error {

	db := orm.NewOrm()
	return db.DoTx(func(ctx context.Context, txOrm orm.TxOrmer) error {

		now := time.Now()
		m := NewRole()
		m.Name = req.Name
		m.Code = req.Code
		m.Memo = req.Memo
		m.UpdatedAt = now
		m.UpdatedBy = uid
		m.CreatedAt = now
		m.CreatedBy = uid
		m.Status = 1

		id, err := txOrm.Insert(m)
		if err != nil {
			return err
		}

		//菜单权限绑定
		roleMenu := make([]RoleMenu, 0)
		mIdArr := strings.Split(req.MIds, ",")
		linq.From(mIdArr).Distinct().ToSlice(&mIdArr)
		for _, v := range mIdArr {
			mId, _ := strconv.ParseUint(v, 10, 64)
			if mId <= 0 {
				continue
			}
			roleMenu = append(roleMenu, RoleMenu{

				RoleID: uint64(id),
				MenuID: mId,
				BModel: BModel{
					CreatedAt: now,
					CreatedBy: uid,
					UpdatedAt: now,
					UpdatedBy: uid,
				},
			})
		}
		if _, err := txOrm.InsertMulti(200, roleMenu); err != nil {
			return err
		}
		return nil

	})

}

type UpdateRoleReq struct {
	ID   uint64 `json:"id"`
	Name string `json:"name"`
	Code string `json:"code"`
	Memo string `json:"memo"`
	MIds string `json:"menu_ids"`
}

func (tb *Role) CountByCode(code string) (count uint64, err error) {

	db := orm.NewOrm()
	c, e := db.QueryTable(tb).Filter("code", code).Count()
	err = e
	count = uint64(c)
	return

}

func (tb *Role) Update(uid uint64, req UpdateRoleReq) error {

	db := orm.NewOrm()
	return db.DoTx(func(ctx context.Context, txOrm orm.TxOrmer) error {

		now := time.Now()
		m := NewRole()
		m.Name = req.Name
		m.Code = req.Code
		m.Memo = req.Memo
		m.UpdatedAt = now
		m.UpdatedBy = uid
		m.ID = req.ID

		_, err := txOrm.Update(m, "name", "code", "memo", "updated_at", "updated_by")
		if err != nil {
			return err
		}

		//删除之前绑定的菜单-角色关联
		rm := NewRoleMenu()
		rm.RoleID = req.ID
		if _, err := txOrm.Delete(rm, "role_id"); err != nil {
			return err
		}

		//菜单权限绑定
		roleMenu := make([]RoleMenu, 0)
		mIdArr := strings.Split(req.MIds, ",")
		linq.From(mIdArr).Distinct().ToSlice(&mIdArr)
		for _, v := range mIdArr {
			mId, _ := strconv.ParseUint(v, 10, 64)
			if mId <= 0 {
				continue
			}
			roleMenu = append(roleMenu, RoleMenu{

				RoleID: uint64(req.ID),
				MenuID: mId,
				BModel: BModel{
					CreatedAt: now,
					CreatedBy: uid,
					UpdatedAt: now,
					UpdatedBy: uid,
				},
			})
		}
		if _, err := txOrm.InsertMulti(200, roleMenu); err != nil {
			return err
		}
		return nil

	})

}

type DeleteRoleReq struct {
	ID uint64 `json:"id"`
}

func (tb *Role) Remove(id, uid uint64) (err error) {

	now := time.Now()
	db := orm.NewOrm()
	tb.Status = 0
	tb.UpdatedAt = now
	tb.UpdatedBy = uid
	tb.ID = id
	_, err = db.Update(tb, "status", "updated_at", "updated_by")
	return

}
